use crate::{error::{Error, Result}};
use crate::db::model::prelude::*;
use crate::db::query_statement::prelude::*;
use crate::db::query_statement::convert_list_bind_value_to_args;
use crate::db::mysql::DbLink;
use crate::db::table::{TableExecutor};
use sqlx_mysql::MySqlArguments;
use std::{sync::Arc};


use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct RangeItem{
    pub start:i64,
    pub end:i64,
    pub name: &'static str,
}

pub fn range_item(start:i64,end:i64,name:&'static str) -> RangeItem{
    RangeItem{
        start,
        end,
        name
    }
}

pub type RangeItemList = Vec<RangeItem>;


pub trait TableRange:Sized{
    const DATABASE_NAME:&'static str; 
    type Executor: TableExecutor;
    type Model: ModelQuery;

    fn get_sql_maker(&self) -> Result<SqlMakerRaw>;

    fn get_range_list() -> RangeItemList;

    fn with_sql_maker(maker:SqlMakerRaw) -> Self;

    fn set_point(&mut self,point:i64) -> &mut Self;

    fn set_range(&mut self,start:i64,end:i64) -> &mut Self;    

    fn get_table_names(&self) ->  Result<Vec<&'static str>>;
    fn get_summary_field_sql(&self) -> String;
    fn get_summary_order_sql(&self) -> String;
    fn get_summary_limit_sql(&self) -> String;
    fn set_summary_field_sql(&mut self,field:&str) -> &mut Self;
    fn set_summary_order_sql(&mut self,order:&str) -> &mut Self;
    fn set_summary_limit_sql(&mut self,limit:&str) -> &mut Self;

    fn with_sql_maker_and_point(maker:SqlMakerRaw,point:i64) -> Self {
        let mut obj = Self::with_sql_maker(maker);
        obj.set_point(point);
        obj
    }

    fn with_sql_maker_and_range(maker:SqlMakerRaw,start:i64,end:i64) -> Self {
        let mut obj = Self::with_sql_maker(maker);
        obj.set_range(start,end);
        obj
    }

    fn get_database_name(&self) -> &str{
        Self::DATABASE_NAME
    }

    fn get_table_name_by_point(point:i64) -> Result<&'static str>{
        for item in Self::get_range_list() {
            if point >= item.start && point < item.end {
                return Ok(item.name);
            }
        }
        Err(Error::Common(format!("point {} for range table if out of range",point)))
    }

    fn get_table_names_by_range(start:i64,end:i64) -> Result<Vec<&'static str>>{
        let first = Self::get_table_name_by_point(start)?;
        let last = Self::get_table_name_by_point(end)?;
        if first == last {
            return Ok(vec![first]);
        }
        println!("range start {} end {}",start,end);
        let mut is_start = false;
        let mut tables = vec![];
        for item in Self::get_range_list() {
            if is_start {
                if item.end >= end {
                    println!("last. item start {} end {}",item.start,item.end);
                    tables.push(item.name);
                    break;
                }
                else{
                    println!("is_start {} item start {} end {}",is_start,item.start,item.end);
                    tables.push(item.name);
                }
            }
            else{
                if item.start <= start && item.end > start {
                    is_start = true;
                    println!("set_start {} item start {} end {}",is_start,item.start,item.end);
                    tables.push(item.name);
                }
            }
        }
        Ok(tables)
    }

    fn get_db_handle(&self) -> Result<Arc<DbLink>>{
        let db_config = self.get_database_name();
        DbLink::instance(db_config)
    }

    fn get_real_sql(sql:&String,table_name:&str) -> String {
        let res = sql.replace(Self::Model::get_table_tpl(), &table_name);
        res
    }

    fn build_executor(self) -> Result<Self::Executor>{ 
        let mut executor = Self::Executor::with();
        let db_link = self.get_db_handle();
        if db_link.is_err() {
            return Err(Error::data_is_empty("get_db_handle failed"));
        }
       let db_link = db_link.unwrap();
        let maker = self.get_sql_maker();
        if maker.is_err() {
            return Err(Error::data_is_empty("get_sql_maker failed"));
        }
        let maker = maker.unwrap();  
        let tables = self.get_table_names()?;
        if tables.is_empty() {
            return Err(Error::data_is_empty("get table name is empty. please set the right range"));
        }
        let table_num = tables.len();
        let tpl_sql = maker.get_sql();
        if table_num == 1 {
            let sql = Self::get_real_sql(&tpl_sql,tables[0]);
            let args = convert_list_bind_value_to_args(maker.get_bind().unwrap_or_default());
            executor.set_db_handle(db_link).set_sql(sql).set_args(args);
            return Ok(executor)
        }
        else{
            // 去掉结尾标志
            let tpl_sql = tpl_sql.replace(";", "");

            let sub_sql = tables.into_iter().map(|table|{
                Self::get_real_sql(&tpl_sql,table)
            }).collect::<Vec<_>>();
            let bind_value = maker.get_bind();
            let replace = match bind_value {
                Some(x) => x,
                None => vec![],
            };
            let bind  ;
            if replace.is_empty() {
                bind = MySqlArguments::default();
            }
            else{
                let mut tmp_val = vec![];
                for _x in 0..table_num{
                    tmp_val.extend(replace.clone());
                }
                bind = convert_list_bind_value_to_args(tmp_val);                
            }
            let sql = format!("SELECT {} from (({})) as tmp_a {} {}",self.get_summary_field_sql(),sub_sql.join(") UNION ALL ("),self.get_summary_order_sql(),self.get_summary_limit_sql());
            println!("sql: {}",sql);
            println!("value: {:?}",bind);
            executor.set_db_handle(db_link).set_sql(sql).set_args(bind);
            return Ok(executor)
        }

       
    }

}


#[macro_export]
macro_rules! lavender_default_table_range_property {
    () => {
        type Model = $crate::db::model::BaseModel;
        type Executor = $crate::db::table::ExecutorBase;
        fn with_sql_maker(maker: $crate::db::query_statement::SqlMakerRaw) -> Self{
            Self{
                sql_maker:Some(maker),
                start: 0,
                end:None,
                field:None,
                order:None,
                limit:None,
            }
        }

        fn get_sql_maker(&self) -> $crate::error::Result<$crate::db::query_statement::SqlMakerRaw> {
            if self.sql_maker.is_none() {
                return Err($crate::error::Error::data_is_empty("sql maker not set or set error"));
            }
            Ok(self.sql_maker.clone().unwrap())
        }   


        fn set_point(&mut self,point:i64) -> &mut Self{
            self.start = point;
            self
        }

        fn set_range(&mut self,start:i64,end:i64) -> &mut Self{
            self.start = start;
            self.end = Some(end);
            self
        }

        fn get_table_names(&self) ->  $crate::error::Result<Vec<&'static str>>{
            if self.end.is_none(){
                return Ok(vec![Self::get_table_name_by_point(self.start)?]);
            }
            else{
                Self::get_table_names_by_range(self.start, self.end.unwrap())
            }
        }

        fn get_summary_field_sql(&self) -> String{
            if self.field.is_none(){
                "*".to_owned()
            }
            else{
                self.field.clone().unwrap()
            }
        }

        fn get_summary_order_sql(&self) -> String{
            if self.order.is_none(){
                "".to_owned()
            }
            else{
            format!("ORDER BY {}", self.order.clone().unwrap())
            }
        }

        fn get_summary_limit_sql(&self) -> String{
            if self.limit.is_none(){
                "".to_owned()
            }
            else{
            format!("LIMIT {}", self.limit.clone().unwrap())
            }
        }

        fn set_summary_field_sql(&mut self,field:&str) -> &mut Self{
            self.field = Some(format!("{}",field));
            self
        }

        fn set_summary_order_sql(&mut self,order:&str) -> &mut Self{
            self.order = Some(format!("{}",order));
            self
        }

        fn set_summary_limit_sql(&mut self,limit:&str) -> &mut Self{
            self.limit = Some(format!("{}",limit));
            self
        }
    };
}

pub mod prelude{
    pub use super::{
        TableRange,
        RangeItem,
        RangeItemList,
        range_item,
    };
}

// pub struct RangeTest{
//     pub sql_maker: Option<SqlMakerRaw>,
//     pub start: i64,
//     pub end: Option<i64>,
//     pub field: Option<String>,
//     pub order: Option<String>,
//     pub limit: Option<String>,
// }

// impl TableRange for RangeTest {
//     const DATABASE_NAME:&'static str = "test";
    
//     fn get_range_list() -> RangeItemList{
//         vec![
            
//         ]
//     }
//     lavender_default_table_range_property!();
// }
